using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;

namespace TCC.Framework
{
    /// <summary>
    /// UI管理器
    /// </summary>
    public class UIManager:BaseManager
    {
        public UIManager(Transform canvas):base()
        {
            _canvasTransform = canvas;
        }

        private Transform _canvasTransform;

        private RectTransform _overlayTransform;
        public RectTransform OverlayTransform=> _overlayTransform = _overlayTransform ?? _canvasTransform.GetChildComponent<RectTransform>("Overlay");

        private RectTransform _cameraTransform;
        public RectTransform CameraTransfrom => _cameraTransform = _cameraTransform ?? _canvasTransform.GetChildComponent<RectTransform>("Camera");

        private Stack<BasePanel> panelStack;
        private Dictionary<string, BasePanel> panelDict;
        private List<BasePanel> panelBuffer;
        public TFunc<int, string> m_changePanleWord;
        private Dictionary<string, Transform> _worldUIDomain;

        private TAction<BasePanel,BasePanel> OnPanelChanged;

        private BasePanel _currentPanel;
        /// <summary>
        /// 当前打开的面板
        /// </summary>
        public BasePanel CurrentPanel
        {
            get => _currentPanel; 
            private set
            {
                OnPanelChanged?.Invoke(_currentPanel, value);
                _currentPanel = value;
            }
        }

        public override void OnInit()
        {
            base.OnInit();
            panelStack = new Stack<BasePanel>();
            panelDict = new Dictionary<string, BasePanel>();
            panelBuffer = new List<BasePanel>();
            _worldUIDomain = new Dictionary<string, Transform>();
            //inlet.WordChangedEvent(()=>ChangedWord());
        }

        /// <summary>
        /// 注册事件UI作用域 （即父物体）
        /// </summary>
        /// <param name="name">名字</param>
        /// <param name="domain">作用域</param>
        public void RegisterWorldUIDomain(string name,Transform domain)
        {
            if (_worldUIDomain.ContainsKey(name))
                Log.Error($"世界UI作用域名称【{name}】被重复注册");
            else
                _worldUIDomain.Add(name, domain);
        }

        /// <summary>
        /// 打开UI
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public void OpenUI<T>(params object[] args) where T : BasePanel => OpenUI(typeof(T), args);

        public void OpenUI(Type type,params object[] args)
        {
            if (panelStack.Count > 0)
                panelStack.Peek().OnPause(args);

            BasePanel panel = GetPanel(type);
            panel.UIEntity.SetActive(true);
            CurrentPanel = panel;
            panel.UIEntity.transform.SetAsLastSibling();
            panelStack.Push(panel);
            panel.OnEnter(args);
            StickyTopic();
        }

        /// <summary>
        /// 预加载UI 加载完成不打开
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public void PreopenUI<T>() => PreopenUI(typeof(T));

        /// <summary>
        /// 预加载UI 加载完成不打开
        /// </summary>
        /// <typeparam name="Type"></typeparam>
        public void PreopenUI(Type type)
        {
            BasePanel panel = GetPanel(type);
            panel.UIEntity.SetActive(false);
        }

        /// <summary>
        /// 置顶UI
        /// </summary>
        private void StickyTopic()
        {
            foreach (var item in panelDict.Values)
                if (item.UIEntity.activeSelf && item.StickyTopic)
                    item.UIEntity.transform.SetAsLastSibling();
        }

        /// <summary>
        /// 关闭UI
        /// </summary>
        public void CloseUI(params object[] args)
        {
            if (panelStack.Count <= 0) return;

            BasePanel toPanel = panelStack.Pop();
            toPanel.UIEntity.SetActive(false);
            toPanel.OnExit(args);

            if (panelStack.Count <= 0) return;
            CurrentPanel = panelStack.Peek();
            CurrentPanel.OnResume(args);
        }

        /// <summary>
        /// 关闭UI
        /// </summary>
        /// <param name="type">UI类型</param>
        /// <param name="isDestroy">是否销毁</param>
        /// <param name="args">参数</param>
        public void CloseUI(Type type,bool isDestroy=false, params object[] args)
        {
            BasePanel panel = GetAlreadyHavePanel(type.FullName);
            if (panel == null) return;
            if (panelStack.Peek() == panel)
                CloseUI(args);
            else
            {
                panelBuffer.Clear();
                if(panel.UIEntity.activeSelf)
                {
                    while (panelStack.Peek() != panel)
                        panelBuffer.Add(panelStack.Pop());
                    panelStack.Pop().UIEntity.SetActive(false);
                    for (int i = panelBuffer.Count - 1; i >= 0; i--)
                        panelStack.Push(panelBuffer[i]);
                }
            }
            if(isDestroy)
            {
                GameObject.DestroyImmediate(panel.UIEntity);
                panelDict.Remove(type.Name);
            }
        }

        /// <summary>
        /// 获取面板
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private BasePanel GetPanel(Type type)
        {
            UIResourceAttribute attribute = type.GetCustomAttribute<UIResourceAttribute>();
            BasePanel panel = panelDict.TryGet(type.FullName);
            if (panel == null)
            {
                panel = Activator.CreateInstance(type) as BasePanel;
                GameObject game = ResetHandler.Instance.ResMagr.LoadAsset<GameObject>(new LoadResHandle<GameObject>(attribute));
                panel.UIEntity = GameObject.Instantiate(game);
                if (attribute.CanvasType.Equals(CanvasType.World))
                {
                    if (string.IsNullOrEmpty(attribute.WorlUIDomain))
                        Log.Error($"世界UI【{game.name}】执行文件【{type.Name}】的作用域为空！");
                    else if (!_worldUIDomain.ContainsKey(attribute.WorlUIDomain))
                        Log.Error($"世界UI【{game.name}】执行文件【{type.Name}】的作用域未注册，请确定其作用域对象挂载了【WorldUIDomain】脚本！");
                    else
                        panel.UIEntity.transform.SetParent(_worldUIDomain[attribute.WorlUIDomain], false);
                }
                else
                    panel.UIEntity.transform.SetParent(attribute.CanvasType.Equals(CanvasType.Overlay) ? OverlayTransform : CameraTransfrom, false);
                panel.ChangeText = ChangedPanleWord;
                panel.OnInit();
                panel.ChangedWord();
                panelDict.Add(type.FullName, panel);
            }

            return panel;
        }

        /// <summary>
        /// 获取已创建的面板
        /// </summary>
        /// <returns></returns>
        public T GetAlreadyHavePanel<T>() where T : BasePanel => panelDict.TryGet(typeof(T).FullName) as T;

        /// <summary>
        /// 获取已创建的面板
        /// </summary>
        /// <returns></returns>
        public BasePanel GetAlreadyHavePanel(string typeFullName)=> panelDict.TryGet(typeFullName);

        /// <summary>
        /// 关闭指定UIPanel
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public void CloseUI<T>(params object[] args)where T:BasePanel
        {
            BasePanel panel = GetAlreadyHavePanel<T>();
            if (panel == null || !panel.UIEntity.activeSelf) return;
            if (panelStack.Peek() == panel)
                CloseUI(args);
            else
            {
                panelBuffer.Clear();
                while(panelStack.Peek()!=panel)
                    panelBuffer.Add(panelStack.Pop());
                panelStack.Pop().UIEntity.SetActive(false);
                for (int i = panelBuffer.Count-1; i >=0; i--)
                    panelStack.Push(panelBuffer[i]);
            }
        }

        public void AddPanelChanged(TAction<BasePanel,BasePanel> action)=> OnPanelChanged += action;

        public void RemovePanelChanged(TAction<BasePanel, BasePanel> action)=> OnPanelChanged -= action;

        private string ChangedPanleWord(int arg0)
        {
            return m_changePanleWord?.Invoke(arg0);
        }

        /// <summary>
        /// 切换语言
        /// </summary>
        public void ChangedWord()
        {
            foreach (var item in panelDict.Values)
            {
                item.ChangedWord();
            }
        }
    }
}
